﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClockLib.Logger
{
    public enum LogLevel
    {
        None,
        Debug,
        Info,
        Warn,
        Error,
    }
    public interface ILogger
    {
        public LogLevel FilterLevel { get; set; }
        public string PrefixTemplate { get; set; }
        public string LoggerName { get; set; }
        public string TimestampFormat { get; set; }
        public void Log(string message, LogLevel level);
        public void Debug(string message);
        public void Info(string message);
        public void Warning(string message);
        public void Error(string message);

    }

    public abstract class BaseLogger : ILogger
    {
        public LogLevel FilterLevel { get; set; } = LogLevel.None;

        public string PrefixTemplate { get; set; } = "[{level}][{timestamp}]";
        public string LoggerName { get; set; } = "Console";
        public string TimestampFormat { get; set; } = "yyyy-MM-dd HH:mm:ss";

        public virtual void Debug(string message)
        {
            Log(message, LogLevel.Debug);
        }

        public virtual void Error(string message)
        {
            Log(message,LogLevel.Error);
        }

        public virtual void Info(string message)
        {
            Log(message, LogLevel.Info);

        }

        public abstract void Log(string message, LogLevel level);

        public virtual void Warning(string message)
        {
            Log(message, LogLevel.Warn);
        }
    }
    public class ConsoleLogger : BaseLogger
    {
        private ConsoleColor defaultFroregroundColor = Console.ForegroundColor;
        private ConsoleColor defaultBackgroundColor = Console.BackgroundColor;

        public ConsoleLogger(LogLevel filterLevel=LogLevel.None)
        {
            FilterLevel = filterLevel;
        }

        private void SetConsoleColor(ConsoleColor foreground,ConsoleColor background)
        {
            Console.BackgroundColor = foreground;
            Console.ForegroundColor = background;
        }
        private void ResetConsoleColor()
        {
            Console.BackgroundColor=defaultBackgroundColor;
            Console.ForegroundColor = defaultFroregroundColor;
        }
        public override void Debug(string message)
        {
            SetConsoleColor(ConsoleColor.White,ConsoleColor.Black);
            Log(message, LogLevel.Debug);
            ResetConsoleColor();
        }

        public override void Error(string message)
        {
            SetConsoleColor(ConsoleColor.DarkRed,ConsoleColor.White);
            Log(message,LogLevel.Error);
            ResetConsoleColor();
        }

        public override void Info(string message)
        {
            SetConsoleColor(ConsoleColor.Green, ConsoleColor.White);
            Log(message, LogLevel.Info);
            ResetConsoleColor();
        }

        public override void Log(string message, LogLevel level)
        {
            if (level<FilterLevel)
            {
                return;
            }
            var time = DateTime.Now.ToString(TimestampFormat);
            var prefix = PrefixTemplate.Replace("{level}", Enum.GetName<LogLevel>(level))
                                .Replace("{timestamp}", time)
                                .Replace("{name}", LoggerName);            
            Console.WriteLine(prefix);
            var lines =message.Split('\n').Select(line => "=> " + line);
            foreach (var line in lines)
            {
                Console.WriteLine(line);
            }
            if (lines.Last().EndsWith('\n'))
            {
                return;
            }
            // Add an empty line
            Console.WriteLine();
        }

        public override void Warning(string message)
        {
            SetConsoleColor(ConsoleColor.DarkYellow, ConsoleColor.White);
            Log(message, LogLevel.Warn);
            ResetConsoleColor();
        }
    }


    public class FileLogger : BaseLogger
    {
         private StreamWriter writer;
        public FileLogger(string filePath)
        {
            var file = File.Open(filePath, FileMode.Append);
            writer = new StreamWriter(file);
        }
        public FileLogger()
        {
            var fileName = DateTime.Now.ToString("yyyy-MM-dd") + ".log";
            var file = File.Open(fileName,FileMode.Append);
            writer = new StreamWriter(file);
        }
        public override void Log(string message, LogLevel level)
        {
            if (level < FilterLevel)
            {
                return;
            }
            var time = DateTime.Now.ToString(TimestampFormat);
            var prefix = PrefixTemplate.Replace("{level}", Enum.GetName<LogLevel>(level))
                                .Replace("{timestamp}", time)
                                .Replace("{name}", LoggerName);
            writer.WriteLine(prefix);
            var lines = message.Split('\n').Select(line => "=> " + line);
            foreach (var line in lines)
            {
                writer.WriteLine(line);
            }
            if (lines.Last().EndsWith('\n'))
            {
                return;
            }
            // Add an empty line
            writer.WriteLine();
            writer.Flush();
        }

        ~FileLogger()
        {
            writer?.Dispose();
        }
    }
}
